﻿using System;
using System.ComponentModel;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;

namespace IpControlsWpf
{
    public delegate void IPv4AddressChangedEventHandler(object sender, EventArgs e);

    /// <summary>
    /// Interaktionslogik für IPv4TextBox.xaml
    /// </summary>
    public partial class IPv4TextBox : UserControl
    {
        private String _tmp;

        public static readonly DependencyProperty AddressProperty = DependencyProperty.Register("Address", typeof(IPAddress), typeof(IPv4TextBox), new UIPropertyMetadata(IPAddress.None, new PropertyChangedCallback(AddressPropertyChanged)));

        /// <summary>
        /// Gets or sets the contained and visible IP address of the control (default = 0.0.0.0).
        /// </summary>
        [Browsable(false)]
        public IPAddress Address
        {
            get
            {
                return (IPAddress)(GetValue(AddressProperty));
            }
            set
            {
                SetValue(AddressProperty, value);
            }
        }

        private static void AddressPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IPv4TextBox target = (IPv4TextBox)d;

            if (target != null)
            {
                target.SetIPAddress((IPAddress)e.NewValue);
            }
        }

        public event IPv4AddressChangedEventHandler AddressChanged;

        public IPv4TextBox()
        {
            InitializeComponent();

            _tmp = String.Empty;
        }

        private delegate void SetIPAddressDelegate(IPAddress value);
        private void SetIPAddress(IPAddress value)
        {
            if (Dispatcher.Thread == Thread.CurrentThread)
            {
                String[] token = new String[4];
                token = value.ToString().Split(new char[] { '.' }, 4);

                tB_Octet0.Text = token[0];
                tB_Octet1.Text = token[1];
                tB_Octet2.Text = token[2];
                tB_Octet3.Text = token[3];

                UpdateLayout();
            }
            else
            {
                SetIPAddressDelegate d = new SetIPAddressDelegate(SetIPAddress);
                Dispatcher.Invoke(DispatcherPriority.Normal, d, value);
            }
        }

        private void tB_Octet_GotFocus(object sender, RoutedEventArgs e)
        {
            TextBox tB = (TextBox)sender;

            _tmp = tB.Text;
            tB.SelectAll();
        }

        private void tB_Octet_LostFocus(object sender, RoutedEventArgs e)
        {
            TextBox tB = (TextBox)sender;

            if (String.IsNullOrEmpty(tB.Text))
            {
                tB.Text = "0";
                tB.Focus();
            }
        }

        private void tB_Octet_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox tB = (TextBox)sender;
            
            if (String.IsNullOrEmpty(tB.Text))
            {
                _tmp = tB.Text;
                return;
            }

            Boolean valid = true;
            for (Int32 i = 0; i < tB.Text.Length; i++)
            {
                valid &= Char.IsDigit(tB.Text[i]);
            }

            Byte result;
            if (!Byte.TryParse(tB.Text, out result) || !valid)
            {
                tB.Text = _tmp;
                tB.CaretIndex = tB.Text.Length;

                return;
            }

            _tmp = tB.Text;

            if (tB.CaretIndex == 3 && tB.Name != "tB_Octet3")
            {
                tB.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));
            }

            IPAddress addr;
            if (tB_Octet3 != null && IPAddress.TryParse(tB_Octet0.Text + "." +
                                                        tB_Octet1.Text + "." +
                                                        tB_Octet2.Text + "." +
                                                        tB_Octet3.Text, out addr))
            {
                Address = addr;

                if (AddressChanged != null)
                {
                    AddressChanged(this, null);
                }
            }
        }

        private void tB_Octet_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            TextBox tB = (TextBox)sender;

            if (e.Key == Key.Left && tB.CaretIndex == 0 && tB.Name != "tB_Octet0")
            {
                tB.MoveFocus(new TraversalRequest(FocusNavigationDirection.Left));

                if (Keyboard.FocusedElement is TextBox)
                {
                    tB = (TextBox)Keyboard.FocusedElement;
                    tB.CaretIndex = tB.Text.Length;
                }

                e.Handled = true;

                return;
            }

            if (e.Key == Key.Right && tB.CaretIndex == tB.Text.Length && tB.Name != "tB_Octet3")
            {
                tB.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));

                if (Keyboard.FocusedElement is TextBox)
                {
                    tB = (TextBox)Keyboard.FocusedElement;
                    tB.CaretIndex = 0;
                }

                e.Handled = true;

                return;
            }
        }

        private void tB_Octet_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            TextBox tB = (TextBox)sender;
            
            Boolean res = true;
            for (Int32 i = 0; i < e.Text.Length; i++)
            {
                res &= Char.IsDigit(e.Text[i]);
            }

            Byte result;
            if (!Byte.TryParse(e.Text, out result))
            {
                res = false;
            }

            if (!res)
            {
                e.Handled = true;
            }

            base.OnPreviewTextInput(e);
        }
    }
}